#include "qrunninghost.h"

#include "qpageloader.h"
#include "qbasedialogwidget.h"
#include "qrunningcore.h"
#include "../sharedLib/qpageinfo.h"
#include "../sharedLib/qpagemanager.h"
#include "../sharedLib/qusermanager.h"
#include "../sharedlib/qbasekeyboard.h"

#include <QVariant>
#include <QScriptValueIterator>
#include <QScriptValue>
#include <QDialog>
#include <QVBoxLayout>
#include <QPushButton>
#include <QApplication>
#include <QKeyEvent>

using namespace RUNNINGLIB;

QRunningHost::QRunningHost(QObject *object):
    QProjectHost(object),
    m_userManager(NULL),
    m_keyboard(NULL),
    m_last_focus_widget(NULL)
{
    connect(this,SIGNAL(exec(QString,QMap<QString,QString>)),this,SLOT(execScript(QString,QMap<QString,QString>)));

    connect(qApp,SIGNAL(focusChanged(QWidget*,QWidget*)),this,SLOT(focus_changed(QWidget*,QWidget*)));

    m_baseWidget=new QWidget;

    qApp->installEventFilter(this);
}

QRunningHost::~QRunningHost()
{
    clear();
    qApp->removeEventFilter(this);
}

void QRunningHost::setPagemanager(SHAREDLIB::QPageManager *manager)
{
    m_pageManager=manager;
    QList<SHAREDLIB::QPageInfo*>   list=m_pageManager->getPages("form");
    foreach(SHAREDLIB::QPageInfo* info,list)
    {
        QWidget* wid=QPageLoader::loadPage(info->get_type(),info->get_data(),this);
        if(wid!=NULL)
        {
            wid->setProperty("objectName",info->get_name());
            wid->setParent(m_baseWidget);
            wid->setVisible(false);
            QAbstractHost *host=(QAbstractHost*)wid->property("host").toInt();
            host->set_type("forms");
            connect(wid,SIGNAL(destroyed()),this,SLOT(pageDestory()));
            m_forms.append(wid);
            m_nameToForms.insert(info->get_name(),wid);
        }
    }

    list=m_pageManager->getPages("keyboard");
    foreach(SHAREDLIB::QPageInfo* info,list)
    {
        QWidget* wid=QPageLoader::loadPage(info->get_type(),info->get_data(),this);
        if(wid!=NULL)
        {
            wid->setProperty("objectName",info->get_name());
            SHAREDLIB::QBaseKeyBoard *keyboard=new SHAREDLIB::QBaseKeyBoard(m_running_window->width(),m_running_window->height(),m_running_window);
            keyboard->set_widget(wid);
            keyboard->setVisible(false);
            QAbstractHost *host=(QAbstractHost*)wid->property("host").toInt();
            host->set_type(info->get_name());
            connect(keyboard,SIGNAL(destroyed()),this,SLOT(keyboardDestory()));
            m_keyboards.append(keyboard);
            m_nameToKeyboards.insert(info->get_name(),keyboard);
        }
    }

    this->init_script_engine(this);
}

void QRunningHost::clear()
{
    m_forms.clear();
    m_keyboards.clear();
}

void QRunningHost::execScript(const QString code, QMap<QString, QString> param)
{
    SHAREDLIB::QAbstractHost    *host=(SHAREDLIB::QAbstractHost*)param.value("widget_host").toInt();

    if(host==NULL)
    {
        return;
    }

    QVariant v=host->getPropertyValue("permission");
    int permission=10;
    if(v.isValid())
    {
        permission=v.toInt();
    }
    if(permission>100)permission=100;
    if(permission<0)permission=0;
    int currentPermission=10;
    if(m_userManager!=NULL)
    {
        QObject *obj=m_userManager->getCurrentUser();
        if(obj!=NULL)
        {
            currentPermission=obj->property("level").toInt();
        }
    }
    if(currentPermission>100)currentPermission=100;
    if(currentPermission<0)currentPermission=0;

    if(currentPermission<permission)
    {
        qDebug("Permission problems!");
        return;
    }

    QMapIterator<QString, QString> it(param);

    QScriptEngine *engine=host->get_script_engine();
    if(engine==NULL)
    {
        qDebug("Script engine empty!");
        return;
    }
    QScriptValue global=engine->globalObject();
    while(it.hasNext())
    {
        it.next();
        global.setProperty(it.key(),it.value());
    }
    engine->setGlobalObject(global);
    engine->evaluate(code);
    if(engine->hasUncaughtException())
    {
        qDebug(engine->uncaughtException().toString().toLocal8Bit());
    }
}

bool QRunningHost::showPage(const QString &name)
{
    QWidget *wid=m_nameToForms.value(name);

    if(wid!=NULL)
    {
        wid->setVisible(true);
        wid->raise();
        return true;
    }
    else
    {
        return false;
    }
}

void QRunningHost::pageDestory()
{
    QWidget* wid=(QWidget*)sender();
    m_forms.removeAll(wid);
    m_nameToForms.remove(wid->objectName());
}

void QRunningHost::keyboardDestory()
{
    QWidget* wid=(QWidget*)sender();
    m_keyboards.removeAll(wid);
    m_nameToKeyboards.remove(wid->objectName());
}

QWidget* QRunningHost::getBaseWidget()
{
    return m_baseWidget;
}

void QRunningHost::firstScript()
{
    QString str=getPropertyValue("befort_start").toString();
    emit_exec(str,QMap<QString,QString>());
}

void QRunningHost::lastScript()
{
    QString str=getPropertyValue("befort_close").toString();
    emit_exec(str,QMap<QString,QString>());
}

void QRunningHost::setUsermanager(SHAREDLIB::QUserManager *manager)
{
    m_userManager=manager;
}

void QRunningHost::setRunningWindow(QRunningWindow *window)
{
    m_running_window=window;
}

void QRunningHost::focus_changed(QWidget *old, QWidget *now)
{
    if(m_last_focus_widget==now)
    {
        return;
    }
    if(now==NULL)
    {
        m_last_focus_widget=NULL;
    }
    QWidget* wid=now;
    while(wid!=NULL)
    {
        if(wid==m_baseWidget)
        {
            break;
        }
        wid=wid->parentWidget();
    }
    if(wid!=NULL && now->property("keyboard").toString()!="")
    {
        m_last_focus_widget=now;
        show_keyboard();
    }
}

bool QRunningHost::eventFilter(QObject *o, QEvent *e)
{
    if(o->isWidgetType() && m_last_focus_widget!=NULL && o!=NULL && e->type()==QEvent::MouseButtonRelease)
    {
        QWidget* wid=(QWidget*)o;
        while(wid!=NULL)
        {
            if(wid==m_last_focus_widget)
            {
                break;
            }
            if(wid==m_keyboard)
            {
                return false;
            }
            wid=wid->parentWidget();
        }
        if(wid==NULL)
        {
            wid=(QWidget*)o;
            if(wid->property("keyboard").toString()=="")
            {
                hide_keyboard();
            }

        }
    }

    return false;
}

void QRunningHost::hide_keyboard()
{
    m_last_focus_widget->clearFocus();
    m_last_focus_widget=NULL;
    if(m_keyboard!=NULL)
    {
        m_keyboard->setVisible(false);
    }
    m_keyboard=NULL;
}

void QRunningHost::show_keyboard()
{
    if(m_last_focus_widget==NULL)
    {
        return;
    }

    QString keyboard_name=m_last_focus_widget->property("keyboard").toString();

    QWidget *keyboard=m_nameToKeyboards.value(keyboard_name);
    if(keyboard==NULL)
    {
        keyboard=m_nameToKeyboards.value("default_keyboard");
    }
    if(keyboard==NULL || m_keyboard==keyboard)
    {
        return;
    }

    if(m_keyboard!=NULL)
    {
        m_keyboard->hide();
    }

    m_keyboard=(SHAREDLIB::QBaseKeyBoard*)keyboard;
    m_keyboard->update_location();
    m_keyboard->setVisible(true);
    m_capslock=false;
}

void QRunningHost::keyboard_send(const QString &key,const QString &text)
{
    if(m_last_focus_widget==NULL)
    {
        return;
    }

    int k=key.toInt();
    if(k==Qt::Key_CapsLock){
        set_capslock(!m_capslock);
    }
    else{
        QKeyEvent keyPress(QEvent::KeyPress, k, Qt::NoModifier,text);
        QApplication::sendEvent(m_last_focus_widget, &keyPress);

        QKeyEvent keyRelease(QEvent::KeyPress, k, Qt::NoModifier, QString());
        QApplication::sendEvent(m_last_focus_widget, &keyRelease);
    }
}

void QRunningHost::set_capslock(bool capslock)
{
    if(m_capslock==capslock)
    {
        return;
    }
    m_capslock=capslock;

    if(m_keyboard!=NULL)
    {
        m_keyboard->set_capslock(capslock);
    }
}
